package com.meizi.codegenerate.generate.clien.domain.repository.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.expr.NameExpr;
import com.meizi.codegenerate.constant.AnnotationSettingValueConstant;
import com.meizi.codegenerate.constant.CharacteristicConstant;
import com.meizi.codegenerate.constant.JavaClassNameConstant;
import com.meizi.codegenerate.constant.TableNameConstant;
import com.meizi.codegenerate.entity.ColumnsEntity;
import com.meizi.codegenerate.entity.ProjectPositionEntity;
import com.meizi.codegenerate.entity.TablesEntity;
import com.meizi.codegenerate.enums.ColumnDataTypeEnum;
import com.meizi.codegenerate.enums.IndexesEnum;
import com.meizi.codegenerate.generate.clien.domain.enums.EnumGenerate;
import com.meizi.codegenerate.packagegenerate.PackageGenerate;
import com.meizi.codegenerate.utils.AnnotationUtils;
import com.meizi.codegenerate.utils.AttributeConvertUtils;
import com.meizi.codegenerate.utils.ColumnUtils;
import com.meizi.codegenerate.utils.JDBCUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Administration
 * @date 2022/11/1 - 15:34 - 星期二
 * @project lambda
 * @package com.meizi.codegenerate.servicegenerate
 * @by 晨
 */
@Slf4j
public class EntityGenerate {

    /**
     * 创建entity 实体
     * @throws IOException
     */
    public static void createEntity () throws IOException{
        // 在相应的路径下创建对应的文件
        ProjectPositionEntity projectPosition = PackageGenerate.getProjectPosition();
        String entityUrl = PackageGenerate.obtainEntityUrl(projectPosition);

        // 获取要生成对应的表名
        List<String> tableNameList = TableNameConstant.getTableNameList();
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();
        LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<>();
        for (String tableName : tableNameList) {
            clearMap(map);

            // 获取数据表的字段名字类型等信息
            List<ColumnsEntity> columnsEntities = JDBCUtils.queryColumns(tableName);
            HashMap<String, String> hashMap = ColumnUtils.columnTypeToImport
                    (ColumnUtils.mapColumnDateType(columnsEntities));
            log.info("import导入 hashMap = {}", hashMap);

            // 获取对数据表得备注信息
            TablesEntity tablesComment = JDBCUtils.queryTablesComment(tableName);
            // 获取对应数据表字段备注信息
            List<ColumnsEntity> columnsCommentList = JDBCUtils.queryColumnsComment(tableName);


            //获取java类名
            String className = AttributeConvertUtils.tableNameToJava
                    (tableName, TableNameConstant.TABLE_PREFIX, true)
                    + JavaClassNameConstant.ENTITY ;
            // 获取完成的文件路径创建文件
            String fullPath = entityUrl + className + TableNameConstant.JAVA;
            log.info("创建entity路径 fullPath = {}", fullPath);

            CompilationUnit compilationUnit = new CompilationUnit();
            // 添加package
            compilationUnit.setPackageDeclaration(PackageGenerate.entityPackage(projectPosition));
            // 导入import
            for (String key : hashMap.keySet()) {
                String value = hashMap.get(key);
                compilationUnit.addImport(value);
            }

            // 添加类文件
            ClassOrInterfaceDeclaration declaration = compilationUnit.addClass(className).setPublic(true);
            //添加类级别注释
            declaration.setJavadocComment(tablesComment.getTableComment());
            //implements Serializable
            declaration.addImplementedType(Serializable.class);
            //添加类级别注解
            declaration.addAnnotation(Data.class);
            map.put(AnnotationSettingValueConstant.CALL_SUPER, AnnotationSettingValueConstant.SET_CALL_SUPER_VALUE);
            declaration.addAnnotation(AnnotationUtils.setAnnotation(EqualsAndHashCode.class, new NodeList<>(),
                    map));
            clearMap(map);

            map.put(AnnotationSettingValueConstant.TABLENAME_VALUE, tableName);
            declaration.addAnnotation(AnnotationUtils.setAnnotation(TableName.class, new NodeList<>(),
                    map));
            clearMap(map);

            // 第一行添加序列化 	private static final Long serialVersionUID = 1L;
            declaration.addFieldWithInitializer
                    (Long.class, "serialVersionUID", new NameExpr().setName("1L") ,
                    Modifier.Keyword.PRIVATE, Modifier.Keyword.STATIC, Modifier.Keyword.FINAL);

            // 实例化属性
            for (ColumnsEntity columnsEntity : columnsEntities) {
                for (ColumnsEntity columnComment : columnsCommentList) {
                    // 是否是主键
                    if (columnComment.getField().equals(columnsEntity.getField())) {
                        if (columnsEntity.getKey().equals(IndexesEnum.PRI.getDesc())) {
                            map.put(AnnotationSettingValueConstant.TABLEID_VALUE, columnsEntity.getField());
                            declaration.addField(
                                    ColumnDataTypeEnum.from(columnsEntity.getType()).getDesc(),
                                    AttributeConvertUtils.columnNameToJava(columnsEntity.getField(), TableNameConstant.COLUMN_PREFIX, false),
                                    Modifier.Keyword.PRIVATE
                            ).setJavadocComment(columnComment.getColumnComment())
                                    .addAnnotation(AnnotationUtils.setAnnotation(TableId.class, new NodeList<>(), map));
                            clearMap(map);

                            // 是否带有逻辑删字段
                        } else if (StringUtils.isNotBlank(columnComment.getColumnComment()) &&
                                columnComment.getColumnComment().contains(CharacteristicConstant.TABLELOGIC)) {

                            // 带有逻辑删除字段，校验逻辑删除注释是否按照规则生成
                            if (checkExplanatoryNoteRule(columnComment.getColumnComment(), map)) {

                                // 带有逻辑删除TableLogic，没有按照规则写注释自动生成 0未删除 1已删除
                            } else {
                                map.put(AnnotationSettingValueConstant.TABLELOGIC_VALUE, AnnotationSettingValueConstant.SET_TABLELOGIC_VALUE);
                                map.put(AnnotationSettingValueConstant.TABLELOGIC_DELVAL, AnnotationSettingValueConstant.SET_TABLELOGIC_DELVAL);
                            }
                            linkedHashMap.put(AnnotationSettingValueConstant.TABLEFIEID_VALUE, columnsEntity.getField());
                            declaration.addField(
                                    ColumnDataTypeEnum.from(columnsEntity.getType()).getDesc(),
                                    AttributeConvertUtils.columnNameToJava(columnsEntity.getField(), TableNameConstant.COLUMN_PREFIX, false),
                                    Modifier.Keyword.PRIVATE
                            ).setJavadocComment(columnComment.getColumnComment())
                                    .addAnnotation(AnnotationUtils.setAnnotation(TableLogic.class, new NodeList<>(), map))
                                    .addAnnotation(AnnotationUtils.setAnnotation(TableField.class, new NodeList<>(), linkedHashMap));
                            clearMap(map);
                            clearMap(linkedHashMap);

                            // 是否带有生成枚举类字段
                        } else if (StringUtils.isNotBlank(columnComment.getColumnComment()) &&
                                    columnComment.getColumnComment().contains(CharacteristicConstant.ENUM)) {
                            EnumGenerate.createEnum(tableName, columnsEntity.getField(), columnComment.getColumnComment());
                            map.put(AnnotationSettingValueConstant.TABLEFIEID_VALUE, columnsEntity.getField());
                            declaration.addField(
                                    ColumnDataTypeEnum.from(columnsEntity.getType()).getDesc(),
                                    AttributeConvertUtils.columnNameToJava(columnsEntity.getField(), TableNameConstant.COLUMN_PREFIX, false),
                                    Modifier.Keyword.PRIVATE
                            ).setJavadocComment(columnComment.getColumnComment())
                                    .addAnnotation(AnnotationUtils.setAnnotation(TableField.class, new NodeList<>(), map));
                            clearMap(map);
                        } else {

                            map.put(AnnotationSettingValueConstant.TABLEFIEID_VALUE, columnsEntity.getField());
                            declaration.addField(
                                    ColumnDataTypeEnum.from(columnsEntity.getType()).getDesc(),
                                    AttributeConvertUtils.columnNameToJava(columnsEntity.getField(), TableNameConstant.COLUMN_PREFIX, false),
                                    Modifier.Keyword.PRIVATE
                            ).setJavadocComment(columnComment.getColumnComment())
                                    .addAnnotation(AnnotationUtils.setAnnotation(TableField.class, new NodeList<>(), map));
                            clearMap(map);
                        }


                    }
                }
            }

            System.out.println(compilationUnit.toString());

            /**
             * 把字符串写入文件
             * 参数1：需要写入的文件，如果文件不存在，将自动创建。  参数2：需要写入的内容
             * 参数3：编码格式     参数4：是否为追加模式（ ture: 追加模式，把字符串追加到原内容后面）
             */
            FileUtils.writeStringToFile(new File(fullPath), compilationUnit.toString(), "UTF-8", false);
        }
    }

    /**
     * 校验逻辑删除注释是否按照规则拼写
     * @param columnComment
     * @param map
     * @return
     */
    private static boolean checkExplanatoryNoteRule(String columnComment, LinkedHashMap<String, Object> map) {
        // 是否包含中英文逗号，
        int on1 = columnComment.indexOf("，");
        int on2 = columnComment.indexOf(",");
        if (on1 != -1 || on2 != -1) {
            String[] split = columnComment.split("[,，]");
            // 切割后是否包含删除规定的字段 等于号 =
            for (String s : split) {
                if (s.contains(CharacteristicConstant.NOT_DELETED_KEY) ||
                        s.contains(CharacteristicConstant.NOT_DELETED_KEY_TOW)) {
                    if (s.indexOf("=") != -1) {
                        String[] split1 = s.split("[=]");

                        String key = "";
                        String value = "";
                        for (String s1 : split1) {
                            if (s1.contains(CharacteristicConstant.NOT_DELETED_KEY)) {
                                key = s1;
                            }
                            if (s1.contains(CharacteristicConstant.NOT_DELETED_KEY_TOW)){
                                key = AnnotationSettingValueConstant.TABLELOGIC_VALUE;
                            }
                            if (s1.contains(CharacteristicConstant.NOT_DELETED_VALUE)) {
                                value = s1;
                            }
                            if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
                                map.put(key, value);
                            }
                        }
                    }
                    continue;
                }

                if (s.contains(CharacteristicConstant.DELETED_KEY) ||
                        s.contains(CharacteristicConstant.DELETED_KEY_TOW)) {
                    if (s.indexOf("=") != -1) {
                        String[] split1 = s.split("[=]");

                        String key = "";
                        String value = "";
                        for (String s1 : split1) {
                            if (s1.contains(CharacteristicConstant.DELETED_KEY)) {
                                key = s1;
                            }
                            if (s1.contains(CharacteristicConstant.DELETED_KEY_TOW)){
                                key = AnnotationSettingValueConstant.TABLELOGIC_DELVAL;
                            }
                            if (s1.contains(CharacteristicConstant.DELETED_VALUE)) {
                                value = s1;
                            }
                            if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
                                map.put(key, value);
                            }
                        }
                    }
                }
            }
        }

        // 校验map是否为空，key：是否正确，value：是否是数字
        boolean valueCheck = false;
        boolean delvalCheck = false;
        if (!CollectionUtils.isEmpty(map)) {
            for (String key : map.keySet()) {
                if (key.equals(AnnotationSettingValueConstant.TABLELOGIC_VALUE)) {
                    Object value = map.get(key);
                    if (value != null) {
                        if (isNumeric(value)) {
                            valueCheck = true;
                        }
                    }
                } else if (key.equals(AnnotationSettingValueConstant.TABLELOGIC_DELVAL)) {
                    Object value = map.get(key);
                    if (value != null) {
                        if (isNumeric(value)) {
                            delvalCheck = true;
                        }
                    }
                }
            }
        }

        return valueCheck && delvalCheck;
    }

    private static boolean isNumeric(Object str) {
        return str.toString().chars().allMatch(Character::isDigit);
    }

    private static void clearMap(Map<String, Object> map) {
        map.clear();
    }
}
